﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace CC.Yacht.Windows.Forms
{
    public partial class GameListBox : UserControl
    {
        #region Constructor
        public GameListBox()
        {
            InitializeComponent();
            HighlightColor = Color.LightGreen;
        }
        #endregion

        #region Private Fields
        private bool _Adding;
        private readonly Dictionary<Guid, Game> _Games = new Dictionary<Guid, Game>();
        private int _LastClientSizeWidth;
        private GameListItem _MouseOverGameListItem;
        #endregion

        #region Public Events
        public event EventHandler CreatingGame;
        public event EventHandler<JoinGameEventArgs> JoiningGame;
        #endregion

        #region Public Properties
        public int Count
        {
            get { return _FlowLayoutPanelMain.Controls.Count; }
        }

        public Color HighlightColor { get; set; }
        #endregion

        #region Private Event Handlers
        private void _ContextMenuStripMain_Closing(object sender, ToolStripDropDownClosingEventArgs e)
        {
            if (_MouseOverGameListItem != null)
            {
                _MouseOverGameListItem.Highlight(false);
            }
        }

        private void _ContextMenuStripMain_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_MouseOverGameListItem != null)
            {
                if (_MouseOverGameListItem.Game.IsPlayable())
                {
                    _MouseOverGameListItem.Highlight(true);
                    _LineToolStripMenuItem1.Visible = true;
                    _JoinGameToolStripMenuItem.Visible = true;
                }
            }
            else
            {
                _LineToolStripMenuItem1.Visible = false;
                _JoinGameToolStripMenuItem.Visible = false;
            }
        }

        private void _CreateGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CreatingGame == null)
            {
                throw new InvalidOperationException("Cannot create game when the CreatingGame event is not attached.");
            }

            OnCreatingGame();
        }

        private void _FlowLayoutPanelMain_ClientSizeChanged(object sender, EventArgs e)
        {
            ResizeControls();
        }

        private void _FlowLayoutPanelMain_MouseEnter(object sender, EventArgs e)
        {
            _MouseOverGameListItem = null;
        }

        // ReSharper disable InconsistentNaming
        /*
        private void _GameListItem_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
            }
        }
        */

        private void _GameListItem_MouseEnter(object sender, EventArgs e)
        {
            if (!_Adding)
            {
                _MouseOverGameListItem = sender as GameListItem;
            }
        }
        // ReSharper restore InconsistentNaming

        private void _JoinGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (JoiningGame == null)
            {
                throw new InvalidOperationException("Cannot join game when the JoiningGame event is not attached.");
            }

            if (_MouseOverGameListItem != null && _MouseOverGameListItem.Game.IsPlayable())
            {
                OnJoiningGame(new JoinGameEventArgs(_MouseOverGameListItem.Game.GameId));
            }
        }
        #endregion

        #region Private Methods
        private void AddGameListItem(Game game)
        {
            if (!_Games.ContainsKey(game.GameId))
            {
                _Games.Add(game.GameId, game);

                GameListItem gameListItem = new GameListItem
                                                              {
                                                                  ContextMenuStrip = _ContextMenuStripMain,
                                                                  Game = game,
                                                                  HighlightColor = HighlightColor,
                                                                  Margin = Padding.Empty,
                                                                  Width = _FlowLayoutPanelMain.ClientSize.Width
                                                              };

                //gameListItem.MouseClick += _GameListItem_MouseClick;
                gameListItem.MouseEnter += _GameListItem_MouseEnter;

                _FlowLayoutPanelMain.Controls.Add(gameListItem);
            }
        }

        private void DisableContextMenu()
        {
            if (_MouseOverGameListItem != null)
            {
                _MouseOverGameListItem.Highlight(false);
            }

            _MouseOverGameListItem = null;
        }

        private GameListItem GetGameListItem(Game game)
        {
            int index;
            return GetGameListItem(game, out index);
        }

        private GameListItem GetGameListItem(Game game, out int index)
        {
            GameListItem gameListItem = null;
            index = _FlowLayoutPanelMain.Controls.IndexOfKey(game.GameId.ToString());

            if (index >= 0)
            {
                gameListItem = _FlowLayoutPanelMain.Controls[index] as GameListItem;
            }

            return gameListItem;
        }

        private void RemoveGameListItem(Game game, bool maintainScrollPosition)
        {
            int index;
            GameListItem gameListItem = GetGameListItem(game, out index);

            if (gameListItem != null)
            {
                _Games.Remove(gameListItem.Game.GameId);
                _FlowLayoutPanelMain.Controls.Remove(gameListItem);

                //gameListItem.MouseClick -= _GameListItem_MouseClick;
                gameListItem.MouseEnter += _GameListItem_MouseEnter;
                gameListItem.Dispose();

                if (maintainScrollPosition)
                {
                    if (index > _FlowLayoutPanelMain.Controls.Count - 1)
                    {
                        index = _FlowLayoutPanelMain.Controls.Count - 1;
                    }

                    if (index > -1)
                    {
                        _FlowLayoutPanelMain.Controls[index].Focus();
                    }
                }
            }
        }

        private void ResizeControls()
        {
            if (_FlowLayoutPanelMain.ClientSize.Width != _LastClientSizeWidth)
            {
                _LastClientSizeWidth = _FlowLayoutPanelMain.ClientSize.Width;

                foreach (Control control in _FlowLayoutPanelMain.Controls)
                {
                    if (control.Width != _LastClientSizeWidth)
                    {
                        control.Width = _LastClientSizeWidth;
                    }
                }
            }
        }
        #endregion

        #region Protected Methods
        protected void OnCreatingGame()
        {
            if (CreatingGame != null)
            {
                CreatingGame(this, EventArgs.Empty);
            }
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            BackColor = Enabled ? SystemColors.Window : SystemColors.Control;
            base.OnEnabledChanged(e);
        }

        protected void OnJoiningGame(JoinGameEventArgs eventArgs)
        {
            if (JoiningGame != null)
            {
                JoiningGame(this, eventArgs);
            }
        }
        #endregion

        #region Public Methods
        public void AddGame(Game game)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(() => AddGame(game)));
            }
            else
            {
                //_FlowLayoutPanelMain.Enabled = false;
                UseWaitCursor = true;
                DisableContextMenu();
                
                _Adding = true;
                
                AddGameListItem(game);
                
                _Adding = false;

                //_FlowLayoutPanelMain.Enabled = true;
                UseWaitCursor = false;
                
                ResizeControls();
            }
        }

        public void Clear()
        {
            List<Game> tempGames = _Games.Select(keyValuePair => keyValuePair.Value).ToList();
            for (int i = tempGames.Count - 1; i >= 0; i--)
            {
                RemoveGame(tempGames[i]);
            }
        }

        public void RemoveGame(Game game)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(() => RemoveGame(game)));
            }
            else
            {
                //_FlowLayoutPanelMain.Enabled = false;
                UseWaitCursor = true;
                DisableContextMenu();

                _Adding = true;

                RemoveGameListItem(game, true);

                _Adding = false;

                //_FlowLayoutPanelMain.Enabled = true;
                UseWaitCursor = false;

                ResizeControls();
            }            
        }

        public void SetGames(List<Game> games)
        {
            Clear();

            for (int i = 0; i < games.Count; i++)
            {
                AddGame(games[i]);
            }
        }

        public void UpdateGame(Game game)
        {
            GameListItem gameListItem = GetGameListItem(game);
            if (gameListItem != null)
            {
                gameListItem.Game = game;
            }
        }
        #endregion
    }
}
